#!/usr/bin/env python3
# -*- coding: utf-8 -*-
##############################################
# @Author: DengLibin 榆霖
# @Date: Create in 2022-03-03 13:50:51
# @Description: 实例属性和类属性
##############################################
'module name'
__author__ = 'DengLibin'
#if __name__ == '__main__':

# 由于Python是动态语言，根据类创建的实例可以任意绑定属性。

# 给实例绑定属性的方法是通过实例变量，或者通过self变量：

class Student(object):
    def __init__(self, name) -> None:
        self.name = name

s = Student('Bob')
s.score = 90

print(s.name, s.score)

# 当我们定义了一个类属性后，这个属性虽然归类所有，但类的所有实例都可以访问到

class Teacher(object):
    name = 'Teacher'
    
# 创建实例
t = Teacher() 
# 打印name属性，因为实例并没有name属性，所以会继续查找class的name属性
print(t.name)

# 打印类的name属性
print(Teacher.name)

# 于实例属性优先级比类属性高，因此，它会屏蔽掉类的name属性
t.name ='王老师'
print(t.name)

# 但是类属性并未消失，用Teacher.name仍然可以访问
print(Teacher.name)

del t.name # 如果删除实例的name属性
# 再次调用t.name，由于实例的name属性没有找到，类的name属性就显示出来了
print(t.name) 

# 从上面的例子可以看出，在编写程序的时候，千万不要对实例属性和类属性使用相同的名字，
# 因为相同名称的实例属性将屏蔽掉类属性，但是当你删除实例属性后，再使用相同的名称，访问到的将是类属性。



# 练习
# 为了统计学生人数，可以给Student类增加一个类属性，每创建一个实例，该属性自动增加：
class Student(object):
    count = 0
    
    def __init__(self, name):
        Student.count = Student.count + 1
        self.name = name
        
# 测试:
fail  = '测试失败!'
if Student.count != 0:
    print(fail)
else:
    bart = Student('Bart')
    if Student.count != 1:
        print(fail)
    else:
        lisa = Student('Bart')
        if Student.count != 2:
            print(fail)
        else:
            print('Students:', Student.count)
            print('测试通过!')

# 小结
# 实例属性属于各个实例所有，互不干扰；

# 类属性属于类所有，所有实例共享一个属性；

# 不要对实例属性和类属性使用相同的名字，否则将产生难以发现的错误。